package com.visualexpress.predict;

import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;

import com.visualexpress.dao.LocationAvertimeDAO;
import com.visualexpress.dao.LocationPairShipmentDAO;
import com.visualexpress.dao.RouteInfoDAO;
import com.visualexpress.dao.TimeLocationDAO;
import com.visualexpress.domain.Location;
import com.visualexpress.domain.LocationAvertime;
import com.visualexpress.domain.LocationPairShipment;
import com.visualexpress.domain.RouteInfo;
import com.visualexpress.domain.Shipment;
import com.visualexpress.domain.TimeLocation;
import com.visualexpress.util.DateUtil;

public class GetBestRoute {
	public static BestRoute getBestRoute(Location loc1, Location loc2) {
		LocationPairShipmentDAO locPairDAO = new LocationPairShipmentDAO();
		TimeLocationDAO timeLocDAO = new TimeLocationDAO();
		LocationAvertimeDAO locAverTimeDAO = new LocationAvertimeDAO();
		RouteInfoDAO routeInfoDAO = new RouteInfoDAO();
		List<LocationPairShipment> lstShipment = locPairDAO.findByLocPair(loc1, loc2);
		int shipmentCount = 0;
		ArrayList<Location> bestRouteLocations = new ArrayList<Location>();
		double minTime = Double.MAX_VALUE, timeForOneShipment;
		for(LocationPairShipment locPairShipment : lstShipment) {
			//for every shipment
			Shipment s = locPairShipment.getShipment();
			List<TimeLocation> timeLocationList = (List<TimeLocation>) timeLocDAO
					.findByShipment(s);
			Collections.sort(timeLocationList,
					new Comparator<TimeLocation>() {
						public int compare(TimeLocation o1, TimeLocation o2) {
							return o1.getLocationNumber() - o2.getLocationNumber(); 
						}
					});
			int i, loc1Ind = -1, loc2Ind = -1;
			for(i = 0; i < timeLocationList.size(); i++) {
				if(timeLocationList.get(i).getLocation().equals(loc1)) {
					loc1Ind = i;
					break;
				}
			}
			for(; i < timeLocationList.size(); i++) {
				if(timeLocationList.get(i).getLocation().equals(loc2)) {
					loc2Ind = i;
					break;
				}
			}
			boolean flag;
			flag = false;
			timeForOneShipment = 0;
			if (loc1Ind < timeLocationList.size()
					&& loc2Ind < timeLocationList.size() && loc1Ind != -1
					&& loc2Ind != -1) {
				flag = true;
				LocationAvertime locAverTime;
				for(i = loc1Ind; i <= loc2Ind; i++) {
					locAverTime = (LocationAvertime)locAverTimeDAO.findByLocation(timeLocationList.get(i).getLocation());
					//todo:refine it
					if(locAverTime == null) {
						flag = false;
						break;
					}
					timeForOneShipment += locAverTime.getTimeStay();
					if (i != loc2Ind) {
						RouteInfo rtInfo = routeInfoDAO.findByStartAndEnd(
								timeLocationList.get(i).getLocation(),
								timeLocationList.get(i + 1).getLocation()).get(
								0);
						if (rtInfo == null) {
							flag = false;
							break;
						}
						timeForOneShipment += rtInfo.getTime();
					}
				}
				if (flag) {
					shipmentCount++;
					if (timeForOneShipment < minTime) {
						minTime = timeForOneShipment;
						bestRouteLocations.clear();
						for (i = loc1Ind; i <= loc2Ind; i++) {
							bestRouteLocations
									.add(timeLocationList.get(i).getLocation());
						}
					}
				} // if flag
			} // if loc1Ind and loc2Ind is valid
		} // for every shipment
		
		if(shipmentCount > 0) {
			BestRoute bestRoute = new BestRoute();
			bestRoute.setRoute(bestRouteLocations);
			bestRoute.setTime(minTime);
			return bestRoute;
		}
		return null;
	}
}
